import { DimensionLocation, Structure, system, Vector3, world } from "@minecraft/server";
import { deferredRegister, DeferredValue } from "gameapi/deferred_register/deferred_register";
import { DynamicJson } from "gameapi/dynamic_data";
import { GAME_API } from "gameapi/instances/gameapi_unique_id";
import { DebugLog } from "gameapi/utils/debug_log";
import { MapChunkInfo } from "./map_chunk_info";

export const MAP_MANAGER_LARGE_MAP_INFO_ID = "large_map_info";

// export let large_map_info_table: DynamicJson<any>;

type StructureType = string | Structure;

export const STRUCTURE_MAX_SIZE_VOLUME: Vector3 = { x: 64, y: 384, z: 64 };

export class StaticMapManager {
    static large_map_info: DeferredValue<DynamicJson<any>> = deferredRegister.register(
        () => new DynamicJson(world, GAME_API.withName(MAP_MANAGER_LARGE_MAP_INFO_ID), {})
    );

    constructor() {}

    public static place(id: StructureType, loc: DimensionLocation) {
        world.structureManager.place(id, loc.dimension, loc);
    }

    //volume
    public static save(id: string, loc: DimensionLocation, volume: Vector3) {
        if (world.structureManager.get(id) != undefined) this.delete(id);

        world.structureManager.createFromWorld(id, loc.dimension, loc, {
            x: loc.x + volume.x - 1,
            y: loc.y + volume.y - 1,
            z: loc.z + volume.z - 1,
        });
    }

    public static *save_large_gen(id: string, loc: DimensionLocation, volume: Vector3) {
        //剩余部分长宽
        let mod_x = volume.x % STRUCTURE_MAX_SIZE_VOLUME.x,
            mod_z = volume.z % STRUCTURE_MAX_SIZE_VOLUME.z;

        let times_x = Math.floor((volume.x - mod_x) / STRUCTURE_MAX_SIZE_VOLUME.x),
            times_z = Math.floor((volume.z - mod_z) / STRUCTURE_MAX_SIZE_VOLUME.z);

        let extra_part_x = mod_x == 0 ? 0 : 1,
            extra_part_z = mod_z == 0 ? 0 : 1;

        //处理每个部分
        for (let i = 0; i < times_x + extra_part_x; i++) {
            for (let j = 0; j < times_z + extra_part_z; j++) {
                const chunk_id = this.get_chunk_id(id, i, j);
                this.save(
                    chunk_id,
                    {
                        y: loc.y,
                        x: loc.x + i * STRUCTURE_MAX_SIZE_VOLUME.x,
                        z: loc.z + j * STRUCTURE_MAX_SIZE_VOLUME.z,
                        dimension: loc.dimension,
                    },
                    {
                        y: volume.y,
                        x: i >= times_x ? mod_x : STRUCTURE_MAX_SIZE_VOLUME.x,
                        z: j >= times_z ? mod_z : STRUCTURE_MAX_SIZE_VOLUME.z,
                    }
                );
                DebugLog.log(`保存了块:${chunk_id}`);
                yield;
            }
        }
        this.large_map_info.value?.update((obj) => {
            let result = obj;
            result[id] = new MapChunkInfo(times_x + extra_part_x, times_z + extra_part_z, volume.x, volume.z);
            return result;
        });
    }

    public static save_large(id: string, loc: DimensionLocation, volume: Vector3) {
        system.runJob(this.save_large_gen(id, loc, volume));
    }

    public static *place_large_gen(id: string, loc: DimensionLocation) {
        const map_chunk_info: MapChunkInfo = this.large_map_info.value?.get()[id];
        if (map_chunk_info != undefined) {
            for (let i = 0; i < map_chunk_info.size_x; i++) {
                for (let j = 0; j < map_chunk_info.size_z; j++) {
                    const chunk_id = this.get_chunk_id(id, i, j);
                    this.place(chunk_id, {
                        y: loc.y,
                        x: loc.x + i * STRUCTURE_MAX_SIZE_VOLUME.x,
                        z: loc.z + j * STRUCTURE_MAX_SIZE_VOLUME.z,
                        dimension: loc.dimension,
                    });
                    DebugLog.log(`放置了块:${chunk_id}`);
                    yield;
                }
            }
        }
    }

    public static place_large(id: string, loc: DimensionLocation) {
        system.runJob(this.place_large_gen(id, loc));
    }

    private static get_chunk_id(id: string, x: number, y: number) {
        return `${id}_${x}_${y}`;
    }

    public static delete(id: StructureType) {
        world.structureManager.delete(id);
    }

    public static delete_large(id: string) {
        let large_map_info_obj = this.large_map_info.value?.get();
        const map_chunk_info: MapChunkInfo = large_map_info_obj[id];

        for (let i = 0; i < map_chunk_info.size_x; i++) {
            for (let j = 0; j < map_chunk_info.size_z; j++) {
                this.delete(this.get_chunk_id(id, i, j));
            }
        }

        large_map_info_obj[id] = undefined;
        this.large_map_info.value?.set(large_map_info_obj);
    }
}
